package com.unisoc.keyguard;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.IBinder;
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;

import com.android.internal.telephony.TelephonyIntents;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.unisoc.telephony.RadioInteractor;
import com.unisoc.keyguard.util.SimLockUtil;
import com.unisoc.sdk.common.telephony.UniTelephonyManager;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

public class KeyguardSimLockMonitor {
    private static final String TAG = "KeyguardSimLockMonitor";

    public static final String SECRECT_CODE_UNLOCK_BY_SIM = "0808";
    public static final String SECRECT_CODE_UNLOCK_BY_NV = "2413";

    private final Context mContext;
    private static KeyguardSimLockMonitor sInstance;
    private RadioInteractor mRadioInteractor = null;
    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    private ArrayList<WeakReference<KeyguardUpdateMonitorCallback>> mCallbacks;

    private boolean mIsAutoShow;
    private boolean mIsBynv;
    private static boolean mSimLockBySim;
    private static boolean mSimLockCanceled;
    private boolean mHideBtn;
    public static boolean mBroadcastReceived;
    // For operator SimLock
    private boolean mHideBtnForOperator;
    private static int mNvState = TelephonyManager.SIM_STATE_READY;

    public static KeyguardSimLockMonitor getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new KeyguardSimLockMonitor(context);
        }
        return sInstance;
    }

    protected KeyguardSimLockMonitor(Context context) {
        mContext = context;

        addRadioInteractorListener();
        mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);

        mIsAutoShow = SimLockUtil.isAutoShow();
        mIsBynv = SimLockUtil.isByNv();
        Log.d(TAG, "mIsAutoShow= " + mIsAutoShow + ", mIsBynv= " + mIsBynv);

        final IntentFilter intentfiler = new IntentFilter();
        intentfiler.addAction("android.provider.Telephony.SECRET_CODE");
        intentfiler.addDataScheme("android_secret_code");
        context.registerReceiverAsUser(mSecrectCodeReceiver, UserHandle.ALL, intentfiler,
                null, null);
        // For operator SimLock
        final IntentFilter filter = new IntentFilter();
        filter.addAction(TelephonyIntents.ACTION_SHOW_OPERATOR_SIMLOCK);
        filter.addAction(TelephonyIntents.ACTION_UPDATE_SIMLOCK_DISMISS_BUTTON);
        context.registerReceiver(mReceiver, filter);
    }

    private void addRadioInteractorListener() {
        ComponentName componentName = new ComponentName("com.android.unisoc.telephony.server",
                "com.android.unisoc.telephony.server.RadioInteractorService");
        mContext.bindService(new Intent().setComponent(componentName), new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d(TAG, "on radioInteractor service connected");
                if (mRadioInteractor == null) {
                    mRadioInteractor = new RadioInteractor(mContext);
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        }, Context.BIND_AUTO_CREATE);
    }

    final BroadcastReceiver mSecrectCodeReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            Log.d(TAG, "received broadcast " + action);
            String host = null;
            Uri uri = intent.getData();
            if (uri != null) {
                host = uri.getHost();
            } else {
                Log.d(TAG, "uri is null");
                return;
            }
            Log.d(TAG, "host: " + host);
            if (SECRECT_CODE_UNLOCK_BY_SIM.equals(host)) {
                /* FL0108100004: Show SimLock secure view when NV state is SimLock
                 * and sim plmn white lists doesn't contains your SIM plmn */
                showUnlockBySim();
            } else if (SECRECT_CODE_UNLOCK_BY_NV.equals(host)) {
                /* FL0108100008: Show SimLock secure view when NV state is SimLock
                 * whitout considering whether your SIM plmn is contained in plmn
                 * white lists or not*/
                showUnlockByNv();
            } else {
                Log.d(TAG, "Unhandle host [" + host + "]");
            }
        }
    };

    /**
     * Receive broadcast to show KeyguardOperatorSimLockView or update 'DISMISS' button on KeyguardSimLockView
     */
    final BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (action.equals(TelephonyIntents.ACTION_SHOW_OPERATOR_SIMLOCK)) {
                mHideBtnForOperator = intent.getBooleanExtra("dismiss_prohibited", true);
                Log.d(TAG, "hide DISMISS button: " + mHideBtnForOperator);
                mCallbacks = mKeyguardUpdateMonitor.getCallbacks();
                for (int i = 0; i < mCallbacks.size(); i++) {
                    KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                    if (cb != null) {
                        cb.onShowSimLockForOperator();
                    }
                }
            } else if (action.equals(TelephonyIntents.ACTION_UPDATE_SIMLOCK_DISMISS_BUTTON)) {
                mHideBtn = intent.getBooleanExtra("dismiss_prohibited", true);
                Log.d(TAG, "hide DISMISS button: " + mHideBtn);
                mBroadcastReceived = true;
                mCallbacks = mKeyguardUpdateMonitor.getCallbacks();
                for (int i = 0; i < mCallbacks.size(); i++) {
                    KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                    if (cb != null) {
                        cb.onUpdateSimLockDismissBtn(mHideBtn);
                    }
                }
            }
        }
    };


    /** FL0108100008: Show SimLock secure view when NV state is SimLock whitout
     *  considering whether your SIM plmn is contained in plmn white lists or not
     */
    private void showUnlockByNv() {
        Log.d(TAG, "showUnlockByNv");
        if (!mIsBynv) {
            Log.d(TAG, "Simlock unlock by nv turned off!");
            return;
        } else {
            setSimLockCanceled(false);
            int isNetworkLock = mRadioInteractor.getSimLockStatus(UniTelephonyManager.UNLOCK_NETWORK, 0);
            int isNetworkSubsetLock = mRadioInteractor.getSimLockStatus(UniTelephonyManager.UNLOCK_NETWORK_SUBSET, 0);
            int isServiceProviderLock = mRadioInteractor.getSimLockStatus(UniTelephonyManager.UNLOCK_SERVICE_PORIVDER, 0);
            int isCorporateLock = mRadioInteractor.getSimLockStatus(UniTelephonyManager.UNLOCK_CORPORATE, 0);
            int isSimLock = mRadioInteractor.getSimLockStatus(UniTelephonyManager.UNLOCK_SIM, 0);

            Log.d(TAG, "isNetworkLock: " + isNetworkLock + ", isNetworkSubsetLock=" + isNetworkSubsetLock +
                    ", isServiceProviderLock= " + isServiceProviderLock + ", isCorporateLock=" + isCorporateLock + ", isSimLock=" + isSimLock);

            // Show simlock secure view if any type is locked state
            if (isNetworkLock > 0 || isNetworkSubsetLock > 0 || isServiceProviderLock > 0
                    || isCorporateLock > 0 || isSimLock > 0) {
                // Sim locked permanently
                if (TelephonyManager.from(mContext).getSimState(0) == UniTelephonyManager.SIM_STATE_SIM_LOCKED_PERMANENTLY) {
                    Log.d(TAG, "SIM is locked permanently!");
                    return;
                }

                //Get state int NV
                mNvState = SimLockUtil.getStateByLockStatus(isNetworkLock, isNetworkSubsetLock, isServiceProviderLock, isCorporateLock, isSimLock);
                mCallbacks = mKeyguardUpdateMonitor.getCallbacks();
                for (int i = 0; i < mCallbacks.size(); i++) {
                    KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                    if (cb != null) {
                        cb.onShowSimLockByNv();
                    }
                }
            } else if (isNetworkLock == 0 && isNetworkSubsetLock == 0 && isServiceProviderLock == 0
                    && isCorporateLock == 0 && isSimLock == 0 ) {
                Toast.makeText(mContext,
                        mContext.getString(R.string.simlock_unlocked),
                        Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(mContext,
                        mContext.getString(R.string.sim_lock_try_later),
                        Toast.LENGTH_LONG).show();
            }
        }
    }

    /** FL0108100004: Show SimLock secure view when NV state is SimLock
     *  and sim plmn white lists doesn't contains your SIM plmn
     */
    private void showUnlockBySim() {
        if (SimLockUtil.isAutoShow()) {
            Log.d(TAG, "SimLock autoshow is enabled, return");
            return;
        } else {
            setSimLockCanceled(false);

            if (SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(TelephonyManager.SIM_STATE_NETWORK_LOCKED))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_NETWORKSUBSET_LOCKED))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_SERVICEPROVIDER_LOCKED))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_CORPORATE_LOCKED))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_SIM_LOCKED))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_NETWORK_LOCKED_PUK))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_NETWORK_SUBSET_LOCKED_PUK))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_SERVICE_PROVIDER_LOCKED_PUK))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_CORPORATE_LOCKED_PUK))
                    || SubscriptionManager.isValidSlotIndex(mKeyguardUpdateMonitor.getNextSlotIdForSimLockState(UniTelephonyManager.SIM_STATE_SIM_LOCKED_PUK))) {
                mSimLockBySim = true;
                mCallbacks = mKeyguardUpdateMonitor.getCallbacks();
                for (int i = 0; i < mCallbacks.size(); i++) {
                    KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                    if (cb != null) {
                        cb.onShowSimLockBySim();
                    }
                }
            } else {
                Toast.makeText(mContext,
                        mContext.getString(R.string.sim_lock_none),
                        Toast.LENGTH_LONG).show();
            }
        }
    }

    /**
     * Return SimLock State config in NV.
     */
    public static int getNvState() {
        return mNvState;
    }

    /**
     * Return true when SimLock is enabled in NV, or state is SimLock
     */
    public static boolean isSimLockStateByUser() {
        if (isSimLockBySim()) {
            return true;
        } else {
            return SimLockUtil.isSimLockState(getNvState());
        }
    }

    /**
     * Report simlock unlocked by nv
     */
    public void reportUnlockedByNV() {
        Log.d(TAG, "reportUnlockedByNV");
        mNvState = TelephonyManager.SIM_STATE_READY;
        for (int i = 0; i < mCallbacks.size(); i++) {
            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
            if (cb != null) {
                cb.onShowSimLockByNv();
            }
        }
    }

    /**
     * Report simlock is unlocked when
     */
    public void reportUnlockedBySIM() {
        Log.d(TAG, "reportUnlockedBySIM");
        mSimLockBySim = false;
    }

    public static boolean isSimLockBySim() {
        return mSimLockBySim;
    }
    /** @} */

    /** SimLock is canceled by clicking DISMISS button @{ */
    public void reportSimLockCanceled(int subId) {
        Log.d(TAG, "reportSimLockByNvCanceled");
        if (SimLockUtil.isByNv()) {
            reportUnlockedByNV();
        } else {
            int slotId = SubscriptionManager.getSlotIndex(subId);
            mKeyguardUpdateMonitor.handleSimStateChangeForSimLock(subId, slotId, TelephonyManager.SIM_STATE_READY);
        }
    }

    public void setSimLockCanceled(boolean canceled) {
        Log.d(TAG, "setSimLockCanceled");
        mSimLockCanceled = canceled;
    }

    public static boolean getSimLockCanceled() {
        return mSimLockCanceled;
    }
    /** @} */

    /**
     * return true if simlock secure view is showing now
     */
    public static boolean isSimLockShowing(int state) {
        boolean isOnekeyLock = SimLockUtil.isOnekeyLock();
        boolean isAutoShow = SimLockUtil.isAutoShow();
        boolean canceled = getSimLockCanceled();
        return !isOnekeyLock && !canceled
                && ((isAutoShow && SimLockUtil.isSimLockState(state)
                        && state != UniTelephonyManager.SIM_STATE_SIM_LOCKED_PERMANENTLY)
                        || isSimLockStateByUser());
    }

    /**
     *
     * @return true 'DISMISS' button for KeyguardSimLockView or KeyguardOperatorSimLockView invisible
     */
    public boolean hideBtnForOperator() {
        return mHideBtnForOperator;
    }

    public boolean hideBtn() {
        return mHideBtn;
    }

    /**
     * KeyguardOperatorSimLockView is canceled by user
     */
    public void reportOperatorSimLockCanceled() {
        TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
        for (int i = 0; i < telephonyManager.getActiveModemCount(); i++) {
            int[] subIds = SubscriptionManager.getSubId(i);
            if (subIds == null || subIds.length == 0) {
                return;
            }
            mKeyguardUpdateMonitor.handleSimStateChangeForSimLock(subIds[0], i, TelephonyManager.SIM_STATE_READY);
        }
    }
}
